package com.aphrodite.ui.widgets.barcode;

/**
 * A <code>BarcodeFactory</code> is used for creating barcodes
 * 
 * @author kentelt
 * 
 */
public final class BarcodeFactory {
	/**
	 * Represents a CODABAR barcode
	 */
	public static final byte CODABAR = 8;
	/**
	 * Represents a CODE128 barcode
	 */
	public static final byte CODE128 = 16;
	public static final int CODE128_A = 0;
	public static final int CODE128_B = 1;
	public static final int CODE128_C = 2;
	/**
	 * Represents a CODE39 barcode
	 */
	public static final byte CODE39 = 10;
	/**
	 * Represents a EAN barcode
	 */
	public static final byte EAN = 6;
	/**
	 * Represents a INT2OF5 barcode
	 */
	public static final byte INT2OF5 = 14;
	/**
	 * Represents a ISBN barcode
	 */
	public static final byte ISBN = 4;

	/**
	 * Represents a U.S POSTNET barcode
	 */
	public static final byte POSTNET = 12;
	/**
	 * Represents a UPC barcode
	 */
	public static final byte UPC = 2;

	/**
	 * 
	 * @param type
	 *            Barcode type, see {@link BarcodeFactory#UPC},
	 *            {@link BarcodeFactory#ISBN}, {@link BarcodeFactory#EAN},
	 *            {@link BarcodeFactory#CODABAR}, {@link BarcodeFactory#CODE39},
	 *            {@link BarcodeFactory#POSTNET}, {@link BarcodeFactory#INT2OF5}
	 * @param data
	 * @throws BarcodeException
	 * @return The barcode according to the <code>type </code> specified. Null
	 *         is returned if <code>type </code> is invalid
	 * 
	 */
	public static Barcode createBarcode(byte type, String data) throws BarcodeException {
		switch (type) {
		case UPC:
			return createUPCABarcode(data);
		case ISBN:
			return createISBNBarcode(data);
		case EAN:
			return createEANBarcode(data);
		case CODABAR:
			return createCodaBarBarcode(data);
		case CODE39:
			return createCode39Barcode(data, true, true);
		case POSTNET:
			return createPostNetBarcode(data);
		case INT2OF5:
			return createInt2Of5Barcode(data);
		case CODE128:
			return createCode128Barcode(data);
		}
		return null;
	}

	/**
	 * Create a Codabar barcode.
	 * <p>
	 * The default height is 50
	 * </p>
	 * 
	 * @param data
	 * @throws BarcodeException
	 * @return
	 */
	public static Barcode createCodaBarBarcode(String data) throws BarcodeException {
		return createCodaBarBarcode(data, 50);
	}

	/**
	 * 
	 * @param data
	 *            The data to encode. numbers (0-9), alphabets(A,B,C,D)
	 * @param height
	 *            of the barcode
	 * @throws BarcodeException
	 * @return
	 */
	public static Barcode createCodaBarBarcode(String data, int height) throws BarcodeException {
		return new CodabarBarcode(data, height);
	}

	// private static BarcodeManager instance;

	// public static BarcodeManager getInstance() {
	// return instance == null ? instance = new BarcodeManager() : instance;
	// }

	/**
	 * Create a Code128 barcode with B character.
	 * <p>
	 * The default height is 50. It fully supports all three available character
	 * sets (A, B and C), and also fully supports code shifts and set changes
	 * on-the-fly, providing an automatic optimisation mode.<br/> The following
	 * is the barcode for <b>"APHRODITE"</b><br/> <img
	 * src="../../../resources/code128.png">
	 * </p>
	 * 
	 * 
	 * @param data
	 * @throws BarcodeException
	 * @return
	 */
	public static Barcode createCode128Barcode(String data) throws BarcodeException {
		return createCode128Barcode(data, 0, 50);

	}

	/**
	 * 
	 * @param data
	 * @param charSet
	 *            {@link BarcodeFactory#CODE128_A},
	 *            {@link BarcodeFactory#CODE128_B},
	 *            {@link BarcodeFactory#CODE128_C}
	 * @param height
	 *@throws BarcodeException
	 * @return
	 */
	public static Barcode createCode128Barcode(String data, int charSet, int height) throws BarcodeException {
		return new Code128Barcode(data, charSet, height);

	}

	/**
	 * Create a Code39 barcode.
	 * <p>
	 * The default height is 50.<br/> Code39 is a barcode symbology that can
	 * encode uppercase letters (A through Z), digits (0 through 9) and a
	 * handful of special characters like the $, -, .,' ',%, +, * sign.<br/> The
	 * following is base39 barcode for the word '<b>J2ME</b>' (without
	 * quotes).<br/> <img src="../../../resources/base39.png">
	 * </p>
	 * 
	 * @param data
	 * @param useCheckSum
	 *            Perform check sum
	 * @param extendedMode
	 *            Use the extended mode characters. This allows you to specify
	 *            special chars in your <code>data</code>
	 * 
	 * @throws BarcodeException
	 *             if <code>data</code> length is 0 or if <code>data</code> null
	 * @return
	 */
	public static Barcode createCode39Barcode(String data, boolean useCheckSum, boolean extendedMode)
			throws BarcodeException {
		return new Code39Barcode(data, useCheckSum, extendedMode);
	}

	/**
	 * Create a Code39 barcode with the given height
	 * 
	 * @param data
	 * @param useCheckSum
	 * @param extendedMode
	 * @param height
	 *            of the barcode
	 * 
	 * @throws BarcodeException
	 * @return
	 */
	public static Barcode createCode39Barcode(String data, boolean useCheckSum, boolean extendedMode, int height)
			throws BarcodeException {
		return new Code39Barcode(data, useCheckSum, extendedMode, height);
	}

	/**
	 * Create a EAN barcode.
	 * 
	 * <p>
	 * The default height is 50. A European Article Number-13 barcode is a
	 * barcoding standard which is a superset of the original 12-digit Universal
	 * Product Code (UPC) system .<br/> The following is a EAN-13 barcode for
	 * "<b>012345678901</b>" <br/><img src="../../../resources/ean.png">
	 * 
	 * </p>
	 * 
	 * @param data
	 *            only 12 numeric digits are accepted
	 * 
	 * @throws BarcodeException
	 *             if <code>data</code> is invalid
	 * @return
	 */
	public static Barcode createEANBarcode(String data) throws BarcodeException {
		return createEANBarcode(data, 50);
	}

	/**
	 * Create a EAN barcode
	 * 
	 * @param data
	 *            only 12 numeric digits are accepted
	 * @param height
	 *            of the barcode
	 * 
	 * @throws BarcodeException
	 * @return
	 */
	public static Barcode createEANBarcode(String data, int height) throws BarcodeException {
		return new EAN13Barcode(data, height);
	}

	/**
	 * Constructs a new Interleave 2 of 5 barcode with the specified data. No
	 * check digit will be added
	 * <p>
	 * The Interleave 2 of 5 barcode requires an even number of characters. At
	 * the same time, a modulo 10 check digit can be used. The default
	 * constructor presumes that if the barcode is of an odd length, then a
	 * check digit is required. This will automaticaly be generated. If the
	 * constructor with the check digit flag is used, the check digit flag is
	 * flase and the length of the barcode is odd, then an exception will be
	 * thrown.<br/> The following is the Interleave 2 of 5 barcode for 1234<br/>
	 * <img src="../../../resources/int20f5.png">
	 * </p>
	 * 
	 * @param data
	 * 
	 * @throws BarcodeException
	 * @return
	 */
	public static Barcode createInt2Of5Barcode(String data) throws BarcodeException {
		return createInt2Of5Barcode(data, false, 50);
	}

	public static Barcode createInt2Of5Barcode(String data, boolean checkDigit, int height) throws BarcodeException {
		return new Int2of5Barcode(data, checkDigit, height);
	}

	/**
	 * Create a ISBN barcode
	 * <p>
	 * Creates a ISBN(Bookland) barcode with the height of 50 pixels
	 * </p>
	 * 
	 * @param data
	 * 
	 * @throws BarcodeException
	 * @return
	 */
	public static Barcode createISBNBarcode(String data) throws BarcodeException {
		return createISBNBarcode(data, 50);
	}

	/**
	 * Create a ISBN barcode.
	 * 
	 * @param data
	 *            Only 12 numeric digits are accepted
	 * @param height
	 *            of the barcode
	 * 
	 * @throws BarcodeException
	 *             if <code>data</code> is invalid
	 * @return
	 */
	public static Barcode createISBNBarcode(String data, int height) throws BarcodeException {
		return new BooklandBarcode(data, height);
	}

	/**
	 * Create a PostNet barcode (US postal service)
	 * <p>
	 * Creates a PostNet barcode with the default height of 20
	 * pixels.<br/>PostNet barcodes only accept numbers from 0-9 with any
	 * length/<br/> The following is a PostNet barcode for the zip code
	 * 12345<br/><img src="../../../resources/postnet.png"> <p/>
	 * 
	 * @param zipcode
	 *            location zip code
	 * 
	 * @throws BarcodeException
	 *             if zip code length is 0 or zipcode is null.
	 * @return
	 */
	public static Barcode createPostNetBarcode(String zipcode) throws BarcodeException {
		return createPostNetBarcode(zipcode, 50);
	}

	/**
	 * Create a PostNet barcode with the given height
	 * 
	 * @param zipcode
	 *            location zip code
	 * @param height
	 *            of the barcode
	 * 
	 * @throws BarcodeException
	 * @return PostNet barcode instance
	 */
	public static Barcode createPostNetBarcode(String zipcode, int height) throws BarcodeException {
		return new PostNetBarcode(zipcode, height);
	}

	/**
	 * Creates a UPC-A barcode using the given data
	 * <p>
	 * The UPC encodes 12 decimal digits as SLLLLLLMRRRRRRE, where S (start) and
	 * E (end) are the bit pattern 101, M (middle) is the bit pattern 01010
	 * (called guard bars), and each L (left) and R (right) are digits, each one
	 * represented by a seven-bit code. This is a total of 95 bits. The
	 * following is a UPC barcode for <b>012345678901</b> <br/><img
	 * src="../../../resources/upccode.png">
	 * </p>
	 * 
	 * @param data
	 *            Data to construct the barcode . Should always have 11 numbers
	 *            between (0-9)
	 * 
	 * @throws BarcodeException
	 *             if the number of digits exceed 12
	 * @throws BarcodeException
	 *             if <code>data</code> contains alphabets
	 * @return UPCA Barcode instance
	 */
	public static Barcode createUPCABarcode(String data) throws BarcodeException {
		return createUPCABarcode(data, false, 50);
	}

	/**
	 * Creates a UPC-A barcode with random weight checking
	 * 
	 * @param data
	 *            Data to construct the barcode
	 * @param randomWeight
	 *            Populate with random weight checking
	 * @param height
	 *            of the barcode
	 * 
	 * @throws BarcodeException
	 *             if the number of digits exceed 12
	 * @throws BarcodeException
	 *             if <code>data</code> contains alphabets
	 * @return A UPCA Barcode
	 */
	public static Barcode createUPCABarcode(String data, boolean randomWeight, int height) throws BarcodeException {
		return new UPCABarcode(data, randomWeight, height);
	}

	/**
	 * Checks if the given <code>key</code> is valid for the specified
	 * <code>type </code>
	 * <p>
	 * Can be checked for all barcode types except Code128 barcodes.
	 * </p>
	 * 
	 * @param type
	 *            Barcode type
	 * @param key
	 *            Single character string
	 * @return True if the given character is valid for <code>type </code>.False
	 *         if <code>type </code> is invalid
	 */
	public static boolean isKeyValid(byte type, String key) {
		switch (type) {
		case UPC:
			return UPCABarcode.isValid(key);
		case ISBN:
			return BooklandBarcode.isValid(key);
		case EAN:
			return EAN13Barcode.isValid(key);
		case CODABAR:
			return CodabarBarcode.isValid(key);
		case CODE39:
			return Code39Barcode.isValid(key, true);
		case POSTNET:
			return PostNetBarcode.isValid(key);
		case INT2OF5:
			return Int2of5Barcode.isValid(key);
		}
		return false;
	}

	private BarcodeFactory() {}
}
